//! 缓存管理模块
//!
//! 提供高性能的缓存管理功能，支持LRU算法、过期清理和线程安全访问
//! 用于缓存服务实例、配置数据等频繁访问的数据

use std::collections::HashMap;
use std::sync::Arc;
use std::time::{Duration, Instant};
use tokio::sync::RwLock;
use tracing::debug;
use nacos_core::ServiceInstance;

/// 缓存条目
#[derive(Debug, Clone)]
pub struct CacheEntry<T> {
    /// 缓存的数据
    pub data: T,
    /// 过期时间
    pub expire_at: Instant,
    /// 最后访问时间
    pub last_access: Instant,
    /// 访问次数
    pub access_count: u64,
}

impl<T> CacheEntry<T> {
    /// 创建新的缓存条目
    pub fn new(data: T, ttl: Duration) -> Self {
        let now = Instant::now();
        Self {
            data,
            expire_at: now + ttl,
            last_access: now,
            access_count: 0,
        }
    }

    /// 检查是否过期
    pub fn is_expired(&self) -> bool {
        Instant::now() >= self.expire_at
    }

    /// 获取数据并更新访问信息
    pub fn get(&mut self) -> &T {
        self.last_access = Instant::now();
        self.access_count += 1;
        &self.data
    }
}

/// LRU缓存管理器
#[derive(Debug)]
pub struct LruCache<K, V> {
    /// 缓存数据
    data: Arc<RwLock<HashMap<K, CacheEntry<V>>>>,
    /// 最大容量
    max_size: usize,
    /// 默认过期时间
    default_ttl: Duration,
}

impl<K, V> LruCache<K, V>
where
    K: std::hash::Hash + Eq + Clone + std::fmt::Debug,
    V: Clone,
{
    /// 创建新的LRU缓存
    pub fn new(max_size: usize, default_ttl: Duration) -> Self {
        Self {
            data: Arc::new(RwLock::new(HashMap::new())),
            max_size,
            default_ttl,
        }
    }

    /// 获取缓存值
    pub async fn get<Q>(&self, key: &Q) -> Option<V>
    where
        K: std::borrow::Borrow<Q>,
        Q: std::hash::Hash + Eq + ?Sized + std::fmt::Debug,
    {
        let mut data = self.data.write().await;
        
        if let Some(entry) = data.get_mut(key) {
            if entry.is_expired() {
                debug!("缓存条目过期: {:?}", key);
                data.remove(key);
                return None;
            }
            
            Some(entry.get().clone())
        } else {
            None
        }
    }

    /// 设置缓存值
    pub async fn set(&self, key: K, value: V) {
        self.set_with_ttl(key, value, self.default_ttl).await;
    }

    /// 设置缓存值并指定过期时间
    pub async fn set_with_ttl(&self, key: K, value: V, ttl: Duration) {
        let mut data = self.data.write().await;
        
        // 如果缓存已满，移除最久未使用的条目
        if data.len() >= self.max_size {
            self.evict_lru(&mut data).await;
        }
        
        let entry = CacheEntry::new(value, ttl);
        data.insert(key.clone(), entry);
        debug!("缓存条目已设置: {:?}", key);
    }

    /// 移除缓存值
    pub async fn remove<Q>(&self, key: &Q) -> Option<V>
    where
        K: std::borrow::Borrow<Q>,
        Q: std::hash::Hash + Eq + ?Sized,
    {
        let mut data = self.data.write().await;
        data.remove(key).map(|entry| entry.data)
    }

    /// 清空缓存
    pub async fn clear(&self) {
        let mut data = self.data.write().await;
        data.clear();
        debug!("缓存已清空");
    }

    /// 获取缓存大小
    pub async fn len(&self) -> usize {
        let data = self.data.read().await;
        data.len()
    }

    /// 检查缓存是否为空
    pub async fn is_empty(&self) -> bool {
        self.len().await == 0
    }

    /// 清理过期条目
    pub async fn cleanup_expired(&self) -> usize {
        let mut data = self.data.write().await;
        let before = data.len();
        
        data.retain(|_, entry| !entry.is_expired());
        
        let after = data.len();
        let cleaned = before - after;
        
        if cleaned > 0 {
            debug!("清理了 {} 个过期缓存条目", cleaned);
        }
        
        cleaned
    }

    /// 获取缓存统计信息
    pub async fn stats(&self) -> CacheStats {
        let data = self.data.read().await;
        let mut total_access = 0u64;
        let mut expired_count = 0usize;
        
        for entry in data.values() {
            total_access += entry.access_count;
            if entry.is_expired() {
                expired_count += 1;
            }
        }
        
        CacheStats {
            size: data.len(),
            max_size: self.max_size,
            total_access,
            expired_count,
        }
    }

    /// 移除最久未使用的条目
    async fn evict_lru(&self, data: &mut HashMap<K, CacheEntry<V>>) {
        if data.is_empty() {
            return;
        }

        let lru_key = data
            .iter()
            .min_by_key(|(_, entry)| entry.last_access)
            .map(|(key, _)| key.clone());

        if let Some(key) = lru_key {
            data.remove(&key);
            debug!("移除最久未使用的缓存条目: {:?}", key);
        }
    }
}

/// 缓存统计信息
#[derive(Debug, Clone)]
pub struct CacheStats {
    /// 当前缓存大小
    pub size: usize,
    /// 最大缓存容量
    pub max_size: usize,
    /// 总访问次数
    pub total_access: u64,
    /// 过期条目数量
    pub expired_count: usize,
}

impl std::fmt::Display for CacheStats {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "CacheStats {{ size: {}/{}, total_access: {}, expired: {} }}",
            self.size, self.max_size, self.total_access, self.expired_count
        )
    }
}

/// 缓存管理器
#[derive(Debug)]
pub struct CacheManager {
    /// 服务实例缓存
    pub service_instances: LruCache<String, Vec<ServiceInstance>>,
    /// 配置数据缓存
    pub config_data: LruCache<String, String>,
    /// 服务列表缓存
    pub service_list: LruCache<String, Vec<String>>,
}

impl CacheManager {
    /// 创建新的缓存管理器
    pub fn new(
        service_instances_capacity: usize,
        config_data_capacity: usize,
        service_list_capacity: usize,
        default_ttl: Duration,
    ) -> Self {
        Self {
            service_instances: LruCache::new(service_instances_capacity, default_ttl),
            config_data: LruCache::new(config_data_capacity, default_ttl),
            service_list: LruCache::new(service_list_capacity, default_ttl),
        }
    }

    /// 清理所有缓存的过期条目
    pub async fn cleanup_all(&self) -> usize {
        let mut total_cleaned = 0;
        total_cleaned += self.service_instances.cleanup_expired().await;
        total_cleaned += self.config_data.cleanup_expired().await;
        total_cleaned += self.service_list.cleanup_expired().await;
        total_cleaned
    }

    /// 获取所有缓存的统计信息
    pub async fn all_stats(&self) -> HashMap<String, CacheStats> {
        let mut stats = HashMap::new();
        stats.insert(
            "service_instances".to_string(),
            self.service_instances.stats().await,
        );
        stats.insert(
            "config_data".to_string(),
            self.config_data.stats().await,
        );
        stats.insert(
            "service_list".to_string(),
            self.service_list.stats().await,
        );
        stats
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use nacos_core::ServiceInstance;
    use std::collections::HashMap;

    #[tokio::test]
    async fn test_cache_entry() {
        let entry = CacheEntry::new("test_data", Duration::from_secs(1));
        assert!(!entry.is_expired());
        
        tokio::time::sleep(Duration::from_millis(1100)).await;
        assert!(entry.is_expired());
    }

    #[tokio::test]
    async fn test_lru_cache() {
        let cache = LruCache::new(2, Duration::from_secs(60));
        
        cache.set("key1".to_string(), "value1".to_string()).await;
        cache.set("key2".to_string(), "value2".to_string()).await;
        
        assert_eq!(cache.get("key1").await, Some("value1".to_string()));
        assert_eq!(cache.get("key2").await, Some("value2".to_string()));
        assert_eq!(cache.len().await, 2);
    }

    #[tokio::test]
    async fn test_cache_expiration() {
        let cache = LruCache::new(10, Duration::from_millis(100));
        
        cache.set_with_ttl("key1".to_string(), "value1".to_string(), Duration::from_millis(50)).await;
        
        assert_eq!(cache.get("key1").await, Some("value1".to_string()));
        
        tokio::time::sleep(Duration::from_millis(60)).await;
        assert_eq!(cache.get("key1").await, None);
    }

    #[tokio::test]
    async fn test_lru_eviction() {
        let cache = LruCache::new(2, Duration::from_secs(60));
        
        cache.set("key1".to_string(), "value1".to_string()).await;
        cache.set("key2".to_string(), "value2".to_string()).await;
        cache.set("key3".to_string(), "value3".to_string()).await; // 这会触发LRU淘汰
        
        assert_eq!(cache.get("key1").await, None); // key1被LRU淘汰
        assert_eq!(cache.get("key2").await, Some("value2".to_string()));
        assert_eq!(cache.get("key3").await, Some("value3".to_string()));
    }

    #[tokio::test]
    async fn test_cache_manager() {
        let manager = CacheManager::new(100, 100, 100, Duration::from_secs(60));
        
        let instance = ServiceInstance::new(
            "test-service".to_string(),
            "test-group".to_string(),
            "127.0.0.1".to_string(),
            8080,
        );
        
        manager.service_instances.set("test".to_string(), vec![instance]).await;
        
        assert_eq!(manager.service_instances.len().await, 1);
        
        let stats = manager.all_stats().await;
        assert!(stats.contains_key("service_instances"));
    }

    #[tokio::test]
    async fn test_cache_stats() {
        let cache = LruCache::new(10, Duration::from_secs(60));
        
        cache.set("key1".to_string(), "value1".to_string()).await;
        cache.get("key1").await;
        cache.get("key1").await;
        
        let stats = cache.stats().await;
        assert_eq!(stats.size, 1);
        assert_eq!(stats.total_access, 2);
        assert_eq!(stats.max_size, 10);
    }
}